﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ST.Core.Util
{
    public static class ByteUtil
    {
        /// <summary>
        /// 判断两个字节数组是否相等
        /// </summary>
        /// <param name="bytes1">第一个字节数组</param>
        /// <param name="bytes2">第二个字节数组</param>
        /// <returns>如果两个数组相等返回true，否则返回false</returns>
        public static bool AreEqual(byte[] bytes1, byte[] bytes2)
        {
            if (bytes1 == null || bytes2 == null)
                return bytes1 == bytes2;

            if (bytes1.Length != bytes2.Length)
                return false;

            for (int i = 0; i < bytes1.Length; i++)
            {
                if (bytes1[i] != bytes2[i])
                    return false;
            }

            return true;
        }

        /// <summary>
        /// 将字节数组转换为16进制字符串，每个字节用空格分隔
        /// </summary>
        /// <param name="bytes">要转换的字节数组</param>
        /// <returns>16进制字符串</returns>
        public static string ToHexString(byte[] bytes)
        {
            if (bytes == null || bytes.Length == 0)
                return string.Empty;

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < bytes.Length; i++)
            {
                sb.Append(bytes[i].ToString("X2"));
                if (i < bytes.Length - 1)
                {
                    sb.Append(" ");
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// 将16进制字符串转换为字节数组
        /// </summary>
        /// <param name="hexString">16进制字符串，可以包含空格分隔符</param>
        /// <returns>转换后的字节数组</returns>
        public static byte[] HexStringToBytes(string hexString)
        {
            if (string.IsNullOrEmpty(hexString))
                return new byte[0];

            // 去除所有空格
            hexString = hexString.Replace(" ", "");

            // 检查字符串长度是否为偶数
            if (hexString.Length % 2 != 0)
                throw new ArgumentException("16进制字符串长度必须为偶数");

            byte[] bytes = new byte[hexString.Length / 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                string byteString = hexString.Substring(i * 2, 2);
                bytes[i] = Convert.ToByte(byteString, 16);
            }

            return bytes;
        }

       /// <summary>
        /// 从Modbus返回的有效数组中提取float值
        /// </summary>
        /// <param name="bytes">有效字节数组</param>
        /// <param name="index">开始位置</param>
        /// <returns>提取的float值</returns>
        public static float GetFloatFromModbus(byte[] bytes, int index)
        {
            if (bytes == null)
                throw new ArgumentNullException(nameof(bytes));
            if (index < 0 || index + 4 > bytes.Length)
                throw new ArgumentOutOfRangeException(nameof(index));

            // Modbus协议通常是大端字节序
            byte[] floatBytes = new byte[4];
            floatBytes[0] = bytes[index + 1];
            floatBytes[1] = bytes[index];
            floatBytes[2] = bytes[index + 3];
            floatBytes[3] = bytes[index + 2];

            return BitConverter.ToSingle(floatBytes, 0);
        }

        /// <summary>
        /// 将Modbus bit数组转换为byte数组，并跳过第一位
        /// </summary>
        /// <param name="data">输入的bit数组</param>
        /// <returns>转换后的byte数组</returns>
        public static byte[] ConvertModbusBitsToBytes(byte[] data)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));

            // 返回数组长度为 (data.Length * 8) + 1
            byte[] result = new byte[(data.Length * 8) + 1];
            
            // 从第二个bit开始转换
            int resultIndex = 1; // 第一位不用，从索引1开始
            for (int i = 0; i < data.Length; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    // 获取每个bit的值，并转换为0x00或0x01
                    result[resultIndex++] = (byte)((data[i] >> j) & 0x01);
                }
            }
            
            return result;
        }

        /// <summary>
        /// 在byte数组前添加一个0
        /// </summary>
        /// <param name="data">原始字节数组</param>
        /// <returns>添加0后的新数组</returns>
        public static byte[] PrependZero(byte[] data)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));

            byte[] result = new byte[data.Length + 1];
            result[0] = 0;
            Array.Copy(data, 0, result, 1, data.Length);
            return result;
        }

        /// <summary>
        /// 获取指定索引的字节
        /// </summary>
        /// <param name="data">字节数组</param>
        /// <param name="index">索引位置</param>
        /// <returns>指定索引的字节</returns>
        public static byte GetByteAt(byte[] data, int index)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));
            if (index < 0 || index >= data.Length)
                throw new ArgumentOutOfRangeException(nameof(index));

            return data[index];
        }

        /// <summary>
        /// 从原数组第二位开始获取UInt16值
        /// </summary>
        /// <param name="data">字节数组</param>
        /// <param name="index">开始位置（从1开始，实际从第二位开始）</param>
        /// <returns>UInt16值</returns>
        public static ushort GetUInt16FromSecondByte(byte[] data, int index)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));
            if (index < 1 || index + 1 >= data.Length)
                throw new ArgumentOutOfRangeException(nameof(index));

            // 从第二位开始计算，index=1对应数组的第二个元素
            int startIndex = index;
            return (ushort)((data[startIndex] << 8) | data[startIndex + 1]);
        }
        
        /// <summary>
        /// 从原数组第二位开始获取整数
        /// </summary>
        /// <param name="data">字节数组</param>
        /// <param name="index">开始位置（从1开始，实际从第二位开始）</param>
        /// <returns>整数</returns>
        public static int GetIntFromSecondByte(byte[] data, int index)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));
            if (index < 1 || index + 3 >= data.Length)
                throw new ArgumentOutOfRangeException(nameof(index));

            // 从第二位开始计算，index=1对应数组的第二个元素
            int startIndex = index;
            return (data[startIndex] << 24) | 
                   (data[startIndex + 1] << 16) | 
                   (data[startIndex + 2] << 8) | 
                   data[startIndex + 3];
        }

        /// <summary>
        /// 从原数组第二位开始获取float值，遵循Modbus字节顺序
        /// </summary>
        /// <param name="data">字节数组</param>
        /// <param name="index">开始位置（从1开始，实际从第二位开始）</param>
        /// <returns>float值</returns>
        public static float GetFloatFromSecondByte(byte[] data, int index)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));
            if (index < 1 || index + 3 >= data.Length)
                throw new ArgumentOutOfRangeException(nameof(index));

            // 从第二位开始计算，index=1对应数组的第二个元素
            int startIndex = index;
            byte[] floatBytes = new byte[4];
            floatBytes[0] = data[startIndex + 1];  // 高字节
            floatBytes[1] = data[startIndex];      // 低字节
            floatBytes[2] = data[startIndex + 3];  // 高字节
            floatBytes[3] = data[startIndex + 2];  // 低字节

            return BitConverter.ToSingle(floatBytes, 0);
        }
        public static void  WriteModbusData(byte[] data,string DataType, string strValue,int Index)
        {
            var newData = GetModbusData(DataType, strValue);
            Array.Copy(newData, 0, data, Index, newData.Length);    
        }
        public static byte[] GetModbusData(string DataType, string strValue)
        {
            if (string.IsNullOrEmpty(strValue))
                throw new ArgumentNullException(nameof(strValue));

            // 去掉末尾的.0或.00
            if (strValue.EndsWith(".0") || strValue.EndsWith(".00")|| strValue.EndsWith(".000")|| strValue.EndsWith(".0000"))
            {
                strValue = strValue.Substring(0, strValue.LastIndexOf('.'));
            }

            switch (DataType.ToLower())
            {
                case "bit":
                    byte bitValue = byte.Parse(strValue);
                    if (bitValue != 0 && bitValue != 1)
                        throw new ArgumentException("Bit值必须为0或1");
                    return new byte[] { bitValue };

                case "uint16":
                    ushort uint16Value = ushort.Parse(strValue);
                    return new byte[] { (byte)(uint16Value >> 8), (byte)uint16Value };

                case "int":
                    int intValue = int.Parse(strValue);
                    return new byte[] 
                    { 
                        (byte)(intValue >> 24), 
                        (byte)(intValue >> 16), 
                        (byte)(intValue >> 8), 
                        (byte)intValue 
                    };

                case "float":
                    float floatValue = float.Parse(strValue);
                    byte[] floatBytes = BitConverter.GetBytes(floatValue);
                    // Modbus字节顺序：高字节在前
                    return new byte[] { floatBytes[1], floatBytes[0], floatBytes[3], floatBytes[2] };

              
                default:
                    throw new ArgumentException("不支持的DataType");
            }
        }

        public static byte[] CalculateModbusCRC16(byte[] data, int begin, int len)
        {
            // 初始化 CRC 寄存器为 0xFFFF
            ushort crc = 0xFFFF;

            // 循环处理每个字节
            for (int i = begin; i < begin + len; i++)
            {
                crc ^= data[i];

                // 对每个字节的 8 位进行处理
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x0001) == 1)
                    {
                        crc = (ushort)((crc >> 1) ^ 0xA001);
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }

            // 将 ushort 类型的 CRC 值转换为 byte 数组
            byte[] crcBytes = new byte[2];
            crcBytes[0] = (byte)(crc & 0xFF);
            crcBytes[1] = (byte)(crc >> 8);

            return crcBytes;
        }
    }
 

}
